package baseFx.tests.common.lock;

import baseFx.common.AutoCloseable;
import baseFx.common.concurrent.Counter;
import baseFx.common.lock.*;
import baseFx.common.concurrent.Task;
import org.junit.Assert;
import org.junit.Test;

import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;

public class QueueLockspaceTest {
    @Test
    public void 一直尝试锁定直到成功为止() throws InterruptedException {
        Counter counter = new Counter();
        CountDownLatch latch = new CountDownLatch(2);
        Semaphore semaphore = new Semaphore(0);
        String key = UUID.randomUUID().toString();
        Task.run(() -> {
            try (AutoCloseable release = getLockspace().queueLock(key)) {
                semaphore.release();
                Task.delay(1000);
                if (counter.get() == 0) {
                    counter.add(1);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            latch.countDown();
        });
        Task.run(() -> {
            try {
                semaphore.acquire();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try (AutoCloseable release = getLockspace().queueLock(key)) {
                if (counter.get() == 1) {
                    counter.add(1);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            latch.countDown();
        });
        latch.await();
        Assert.assertEquals(counter.get(), 2);
    }

    @Test
    public void 超时后抛出异常() throws InterruptedException {
        Counter counter = new Counter();
        CountDownLatch latch = new CountDownLatch(2);
        Semaphore semaphore = new Semaphore(0);
        String key = UUID.randomUUID().toString();
        Task.run(() -> {
            try (AutoCloseable release = getLockspace().queueLock(key)) {
                semaphore.release();
                Task.delay(2000);
                counter.add(1);
            }
            latch.countDown();
        });
        Task.run(() -> {
            try {
                semaphore.acquire();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try (AutoCloseable release = getLockspace().queueLock(key, 1)) {
                Task.delay(1000);
            } catch (AbortTimeoutException e) {
                counter.add(1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            latch.countDown();
        });
        latch.await();
        Assert.assertEquals(counter.get(), 2);
    }

    @Test
    public void 轮流锁定成功() throws InterruptedException {
        String key = UUID.randomUUID().toString();
        int size = 50;
        CountDownLatch latch = new CountDownLatch(size);
        Counter counter = new Counter();
        Lockspace lockspace = getLockspace();

        for (int i = 0; i < size; i++) {
            Task.run(() -> {
                try (AutoCloseable ac = lockspace.queueLock(key)) {
                    counter.add(1);
                } finally {
                    latch.countDown();
                }
            });
        }
        latch.await();
        Assert.assertEquals(size, counter.get());
    }

    protected Lockspace getLockspace() {
        return new AppLockspace();
        //return new RedisLockspace(new JedisPool());
    }
}
